package com.aliyun.messagemgt.application.service.Impl;

import com.alibaba.cola.dto.MultiResponse;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.messagemgt.application.service.*;
import com.aliyun.messagemgt.application.service.mq.MessageQueenService;
import com.aliyun.messagemgt.common.constant.PushConstant;
import com.aliyun.messagemgt.common.convert.MsgPushVOConverter;
import com.aliyun.messagemgt.common.dto.response.ResultMap;
import com.aliyun.messagemgt.common.dto.send.*;
import com.aliyun.messagemgt.common.enums.IsEnabledEnum;
import com.aliyun.messagemgt.common.enums.MediaLimitEnum;
import com.aliyun.messagemgt.common.enums.PushResultEnum;
import com.aliyun.messagemgt.common.enums.SourceTypeEnum;
import com.aliyun.messagemgt.common.errorcode.push.CommonErrorCode;
import com.aliyun.messagemgt.common.exceptions.BaseException;
import com.aliyun.messagemgt.domain.repository.IBaseMessageTemplateParamService;
import com.aliyun.messagemgt.domain.repository.IBaseMessageTemplateService;
import com.aliyun.messagemgt.domain.repository.IBaseTenantUserRepository;
import com.aliyun.messagemgt.dto.BaseMessageTemplateDTO;
import com.aliyun.messagemgt.dto.BaseMessageTemplateParamDTO;
import com.aliyun.messagemgt.dto.MsgHandleLog;
import com.aliyun.messagemgt.dto.MsgSource;
import com.aliyun.messagemgt.dto.base.BaseMessageSourceDTO;
import com.aliyun.messagemgt.dto.base.BaseTenantDTO;
import com.aliyun.messagemgt.dto.base.BaseTenantUserDTO;
import com.aliyun.messagemgt.dto.out.MsgPushResponseDTO;
import com.aliyun.messagemgt.dto.push.InterfaceLog;
import com.aliyun.messagemgt.dto.query.MessageTemplateQuery;
import com.aliyun.messagemgt.dto.query.MsgQuery;
import com.aliyun.messagemgt.repository.mappers.BaseMessageTemplateMapper;
import com.aliyun.messagemgt.sendplugin.SendStrategyContext;
import com.aliyun.messagemgt.util.PlaceHolderUtils;
import com.aliyun.messagemgt.util.SpringContextUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * Created with IDEA
 *
 * @author:zhangxingxing 0027012120
 * @date:2019/1/22
 * @time:19:41
 */
@Service
public class PushServiceImpl implements PushService {

    private static final Logger logger = LoggerFactory.getLogger(PushServiceImpl.class);

    @Autowired
    private SendStrategyContext sendStrategyContext;
    @Autowired
    private MsgRecordService msgRecordService;
    @Autowired
    private MsgHandleLogService msgHandleLogService;
    @Autowired
    private MsgMediaHandler msgMediaHandler;
    @Autowired
    private UserMsgRestrain userMsgRestrain;
    @Autowired
    private ReceiverHandle receiverHandle;
    @Autowired
    private MsgSourceService msgSourceService;
    @Autowired
    private MsgFlowControl msgFlowControl;
    @Autowired
    private MsgResend msgResend;
    @Autowired
    private MessageQueenService messageQueenService;
    @Resource
    private InterFaceLogService interFaceLogService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private BaseMessageTemplateMapper baseMessageTemplateMapper;

    @Autowired
    private IBaseMessageTemplateService baseMessageTemplateService;
    @Autowired
    private IBaseMessageTemplateParamService baseMessageTemplateParamService;
    @Autowired
    private PushChannelMap pushChannelMap;

    @Autowired
    private IBaseTenantUserRepository baseTenantUserRepository;
    @Autowired
    private BaseMessageSourceService baseMessageSourceService;
    @Autowired
    private BaseReceiveGroupService baseReceiveGroupService;
    @Autowired
    private BaseTenantService baseTenantService;

    /**
     * 推送的处理流程为
     * 1. 推送目标处理，将参数中的组织机构直接转化为个人列表,去重，@all过滤，实际推送者为receiver
     * 2. 流控
     * 3. 富媒体转存 + 发送文件大小判断
     * 4. 针对个人进行短时间内的消息去重
     * 5. 推送服务
     * 6. 发送失败的数据重新发送（看错误码 目前受到流控的和重复消息的不会重发）
     * 7. msgRecord信息插入
     * 8. 全流程的处理日志结果集合插入
     * 9. 发送统计mq
     *
     * @param msgRecordVos
     */
    public void push(List<MsgRecordVO> msgRecordVos) {
        if (msgRecordVos == null || msgRecordVos.isEmpty()) {
            return;
        }
        // 1. 推送目标处理，将参数中的组织机构直接转化为个人列表,去重
        receiverHandle.receiverCalNew(msgRecordVos);
        logger.info("推送目标处理，将参数中的组织机构直接转化为个人列表,去重");
        // 2. 富媒体转存 + 发送文件大小判断,替换原先实体中的url信息
        msgMediaHandler.findMediaAndTransfer(msgRecordVos);
        logger.info("富媒体转存 + 发送文件大小判断,替换原先实体中的url信息");
        // 3. 限流
        // msgFlowControl.flowControl(msgRecordVos, msgSource);
        // 4. 针对个人进行短时间内的消息去重
        userMsgRestrain.restrain(msgRecordVos);
        logger.info("针对个人进行短时间内的消息去重");
        List<Receiver> receivers = msgRecordVos.get(0).getReceivers();
        if (CollectionUtils.isEmpty(receivers)) {
            return;
        }
        // 5. 插入msgRecord信息内容
        msgRecordService.batchMsgRecordInsert(msgRecordVos);
        logger.info("插入msgRecord信息内容");
        // 6. 实际推送服务
        sendStrategyContext.sendMessage(msgRecordVos);
        logger.info("推送消息结束");
        // 7.更新消息记录表中的状态,pushResultCode都为1时说明所有人发送成功
        msgRecordVos.forEach(
                msgRecordVO -> {
                    Set<Integer> pushResultCodeSet = msgRecordVO.getResults().stream().map(MsgMiddleResult::getPushResultCode).collect(Collectors.toSet());
                    if (CollectionUtils.isNotEmpty(pushResultCodeSet)
                            && (pushResultCodeSet.size() != 1
                            || !PushResultEnum.PUSH_SUCCESS.getErrorCode().equals(pushResultCodeSet.iterator().next()))) {
                        msgRecordVO.setStatus(false);
                    }
                    msgRecordService.updateMsgRecordStatus(msgRecordVO);
                }
        );
        // 8. 全流程的处理日志结果集合插入
        msgHandleLogService.batchMsgHandleLogInsert(msgRecordVos);
        logger.info("全流程的处理日志结果集合插入");
    }

//    @Override
//    public void simplePush(MsgRecordVO msgRecordVO) {
//        msgRecordVoParamCheck(msgRecordVO);
//        msgRecordVO.setMessageType(MessageTypeUtil.generateWechatTextCardMsg())
//                .setMsgTitle(msgRecordVO.getMsgTitle())
//                .setMsgDescription(msgRecordVO.getMsgDescription())
//                .setCommentType(PushConstant.TEXT_COMMENT_TYPE)
//                .setMsgSourceId(PushConstant.MSG_ZNTS_ID)
//                .setMsgSourceName(PushConstant.MSG_ZNTS_NAME)
//                .setMsgSourceType(PushConstant.ZNTS_MSG_SOURCE_TYPE);
//        // 智推简单接口推送
//        MsgSource msgSource = msgSourceService.getMsgSourceBySourceCode(PushConstant.MSG_ZNTS_ID);
//        // push(Arrays.asList(msgRecordVO), msgSource);
//    }

//    @Override
//    public void apiPush(MsgPushVO msgPushVO) {
//        // 参数有效性验证
//        msgPushVoParamCheck(msgPushVO);
//        String msgSourceId = msgPushVO.getMsgSourceId();
//        MsgSource msgSource = msgSourceService.getMsgSourceBySourceCode(msgSourceId);
//        // 消息源有效性验证
//        msgSourceCheck(msgSource);
//        // 将消息源中关键数据填入MsgRecordVO中
//        List<MsgRecordVO> msgRecordVos = msgPushVO.getMsgList();
//        if (msgRecordVos != null) {
//            for (MsgRecordVO msgRecordVO : msgRecordVos) {
//                if (StringUtils.isEmpty(msgPushVO.getMessageType())) {
//                    msgRecordVO.setMessageType(MessageTypeUtil.generateWechatTextCardMsg());
//                } else {
//                    msgRecordVO.setMessageType(msgPushVO.getMessageType());
//                }
//
//                msgRecordVO.setMsgSourceId(msgSource.getSourceCode())
//                        .setMsgSourceName(msgSource.getSourceName())
//                        .setMsgSourceType(PushConstant.API_MSG_SOURCE_TYPE)
//                        .setOwnerDept(msgSource.getOwnerDept())
//                        .setOwnerDeptName(msgSource.getOwnerDeptName())
//                        .setPushChannelId(msgSource.getPushChannelId().toString())
//                        .setPushChannelName(msgSource.getPushChannelName())
//                        .setPushChannelType(msgSource.getPushChannelType().toString())
//                        .setContents(msgRecordVO.getContents())
//                        .setCommentType(PushConstant.TEXT_COMMENT_TYPE);
//            }
//        }
//        //push(msgRecordVos, msgSource);
//        //msgHandleLogService.batchMsgHandleLogInsert(msgRecordVos);
//        insertInterfaceLog(msgPushVO);
//    }

    @Override
    @Transactional
    public MultiResponse<SingleResponse<MsgPushResponseDTO>> apiPush(MsgPushDTO msgPushDTO) {
        logger.info("PushServiceImpl.apiPush msgPushDTO:{}", msgPushDTO);
        List<MsgPushDTO.MsgRecordDTO> msgRecordList = msgPushDTO.getMsgRecordList();
        List<MsgRecordVO> result = new ArrayList<>();
        // 新接口基于原apiPush进行升级改造，将MsgRecordDTO转换为MsgRecordVO
        for (MsgPushDTO.MsgRecordDTO msgRecordDTO : msgRecordList) {
            msgRecordDTOParamCheck(msgRecordDTO);
            // 1.转换msgPushDTO为MsgRecordVO
            MsgRecordVO msgRecordVO = MsgPushVOConverter.INSTANCE.msgRecordDTO2msgRecordVO(msgRecordDTO);
            // 2.根据租户编码、场景编码查询发送任务配置
            MsgSource msgSource = processMsgSource(msgRecordVO);
            // 3.处理场景信息
            processScene(msgRecordVO, msgRecordDTO, msgSource);
            // 4.处理消息内容，如果有模板，替换模板中的占位符，传输报文中如果没有模板，则从消息源中获取模板信息，传输报文参数优先
            processContents(msgRecordVO, msgRecordDTO, msgSource);
            // 5.处理渠道，传输报文中如果没有渠道，则从消息源中获取渠道信息，传输报文参数优先
            processReceiveChannel(msgRecordVO, msgSource);
            // 6.处理接收组，传输报文中如果没有接收组，则从消息源中获取接收组信息，传输报文参数优先
            processReceiveRangeInfo(msgRecordVO, msgRecordDTO, msgSource);
            // 7.处理重试机制
            processFailureResend(msgRecordVO, msgRecordDTO, msgSource);
            // 8.发送消息
            List<MsgRecordVO> msgRecordVOS = new ArrayList<>();
            msgRecordVOS.add(msgRecordVO);
            push(msgRecordVOS);
            // 9.记录接口日志
            insertInterfaceLogNew(msgRecordVO, msgSource);
            result.addAll(msgRecordVOS);
        }
        // 10.构建响应体
        return buildResponse(result);
    }

    private void processScene(MsgRecordVO msgRecordVO, MsgPushDTO.MsgRecordDTO msgRecordDTO, MsgSource msgSource) {
        BaseMessageSourceDTO baseMessageSourceDTO = baseMessageSourceService.getByTenantCodeAndSceneCode(msgRecordVO.getTenantCode(), msgRecordVO.getSceneCode());
        if (Objects.isNull(baseMessageSourceDTO)) {
            throw new BaseException(CommonErrorCode.SCENE_IS_NULL);
        }
        msgRecordVO.setSceneName(baseMessageSourceDTO.getSceneName());
        msgRecordVO.setMsgSourceId(baseMessageSourceDTO.getId());
        msgRecordVO.setMsgSourceCode(baseMessageSourceDTO.getSourceCode());
        msgRecordVO.setMsgSourceName(baseMessageSourceDTO.getSourceName());
    }

    @Override
    public MultiResponse<SingleResponse<MsgPushResponseDTO>> buildResponse(List<MsgRecordVO> msgRecordVOS) {
        AtomicBoolean success = new AtomicBoolean(true);
        List<SingleResponse<MsgPushResponseDTO>> singleResponseList = msgRecordVOS.stream().map(
                msgRecordVO -> {
                    SingleResponse<MsgPushResponseDTO> singleResponse = processSingleResponse(msgRecordVO);
                    if (!singleResponse.isSuccess()) {
                        success.set(false);
                    }
                    return singleResponse;
                }
        ).collect(Collectors.toList());
        MultiResponse<SingleResponse<MsgPushResponseDTO>> multiResponse = MultiResponse.of(singleResponseList);
        multiResponse.setSuccess(success.get());
        return multiResponse;
    }

    @Override
    public SingleResponse<MsgPushResponseDTO> processSingleResponse(MsgRecordVO msgRecordVO) {
        SingleResponse<MsgPushResponseDTO> singleResponse = new SingleResponse<>();
        MsgPushResponseDTO msgPushResponseDTO = new MsgPushResponseDTO();
        msgPushResponseDTO.setOrgMessageId(msgRecordVO.getUniqueId());
        msgPushResponseDTO.setNcMessageId(String.valueOf(msgRecordVO.getMsgId()));
        singleResponse.setData(msgPushResponseDTO);
        List<MsgMiddleResult> results = msgRecordVO.getResults();
        if (CollectionUtils.isEmpty(results)) {
            singleResponse.setSuccess(true);
            singleResponse.setErrCode(PushResultEnum.PUSH_SUCCESS.getErrorCode().toString());
            singleResponse.setErrMessage(PushResultEnum.PUSH_SUCCESS.getDescription());
            return singleResponse;
        }
        StringBuilder errCode = new StringBuilder();
        StringBuilder errMessage = new StringBuilder();
        Set<Integer> pushResultCodeSet = new HashSet<>();
        results.forEach(
                msgMiddleResult -> {
                    Integer pushResultCode = msgMiddleResult.getPushResultCode();
                    pushResultCodeSet.add(pushResultCode);
                    errCode.append(pushResultCode).append(";");
                    errMessage.append(msgMiddleResult.getPushResultDescription()).append(";");
                }
        );
        String errCodeStr = errCode.substring(0, errCode.length() - 1);
        if (pushResultCodeSet.size() == 1
                && PushResultEnum.PUSH_SUCCESS.getErrorCode().equals(pushResultCodeSet.iterator().next())) {
            singleResponse.setSuccess(true);
        }
        singleResponse.setErrCode(errCodeStr);
        singleResponse.setErrMessage(errMessage.substring(0, errMessage.length() - 1));
        return singleResponse;
    }

    private void processReceiveRangeInfo(MsgRecordVO msgRecordVO, MsgPushDTO.MsgRecordDTO msgRecordDTO, MsgSource msgSource) {
        MsgPushDTO.MsgRecordDTO.ReceiveRangeInfo receiveRangeInfo = msgRecordVO.getReceiveRangeInfo();
        String rangeTransType = receiveRangeInfo.getRangeTransType();
        if ("GROUP".equals(rangeTransType) && CollectionUtils.isEmpty(receiveRangeInfo.getReceiveGroupCodes())) {
            // 1.消息源有效性验证
            msgSourceCheck(msgSource);
            // 2.设置接收组
            receiveRangeInfo = new MsgPushDTO.MsgRecordDTO.ReceiveRangeInfo();
            receiveRangeInfo.setRangeTransType("GROUP");
            List<String> receiveGroupCodes = new ArrayList<>();
            receiveGroupCodes.add(msgSource.getReceiveGroupCode());
            receiveRangeInfo.setReceiveGroupCodes(receiveGroupCodes);
            msgRecordVO.setReceiveRangeInfo(receiveRangeInfo);
        }
    }


    private MsgSource processMsgSource(MsgRecordVO msgRecordVO) {
        MsgQuery qry = new MsgQuery();
        qry.setTenantCode(msgRecordVO.getTenantCode());
        qry.setSceneCode(msgRecordVO.getSceneCode());
        qry.setStateDelete(0);
        qry.setIsEnabled(IsEnabledEnum.Y.getCode());
        return msgSourceService.getMsgSource(qry);
    }

    private void processFailureResend(MsgRecordVO msgRecordVO, MsgPushDTO.MsgRecordDTO msgRecordDTO, MsgSource msgSource) {
        // 重试次数
        Integer failureResendTimes = msgRecordDTO.getFailureResendTimes();
        // 重试时间间隔
        Integer failureResendInterval = msgRecordDTO.getFailureResendInterval();
        if (Objects.nonNull(failureResendTimes) && Objects.nonNull(failureResendInterval)) {
            msgRecordVO.setFailureResendTimes(failureResendTimes + 1);
            msgRecordVO.setFailureResendInterval(failureResendInterval);
            return;
        }
        Integer failureResendTimesBymsgSource = msgSource == null ? null : msgSource.getFailureResendTimes();
        Integer failureResendIntervalBymsgSource = msgSource == null ? null : msgSource.getFailureResendInterval();
        failureResendTimes = Optional.ofNullable(failureResendTimes).orElse(failureResendTimesBymsgSource);
        failureResendInterval = Optional.ofNullable(failureResendInterval).orElse(failureResendIntervalBymsgSource);
        // 设置重试次数，重试间隔时间，默认重试1次，间隔1分钟
        msgRecordVO.setFailureResendTimes(failureResendTimes == null ? 1 : failureResendTimes + 1);
        msgRecordVO.setFailureResendInterval(failureResendInterval == null ? 1 : failureResendInterval);
    }

    @Override
    @Transactional
    public ResultMap<MsgPushResponseDTO> apiRePush(Long msgId) {
        // 1.获取失败的消息记录，根据渠道-接收者类型构建多条消息发送记录进行消息发送
        List<MsgRecordVO> msgRecordVOList = msgRecordService.getMsgRecordVOList(msgId);
        if (CollectionUtils.isEmpty(msgRecordVOList)) {
            ResultMap<MsgPushResponseDTO> resultMap = new ResultMap<>();
            resultMap.setSuccess(false);
            resultMap.setErrMsg(PushResultEnum.PUSH_RECEIVE_RANGEINFO_ISNULL.getDescription());
            return resultMap;
        }
        // 2.推送目标处理，将参数中的组织机构直接转化为个人列表,去重
        receiverHandle.receiverCalNew(msgRecordVOList);
        // 3.发送消息
        sendStrategyContext.sendMessage(msgRecordVOList);
        for (MsgRecordVO msgRecordVO : msgRecordVOList) {
            // 4.重发成功后，更新消息记录子表中的状态
            List<MsgMiddleResult> results = msgRecordVO.getResults();
            List<Receiver> receiverList = new ArrayList<>();
            results.stream().filter(obj -> PushResultEnum.PUSH_SUCCESS.getErrorCode().equals(obj.getPushResultCode()))
                    .forEach(
                            msgMiddleResult -> {
                                List<Receiver> receivers = msgMiddleResult.getReceivers();
                                receiverList.addAll(receivers);
                            }
                    );
            if (CollectionUtils.isNotEmpty(receiverList)) {
                MsgHandleLog msgHandleLog = new MsgHandleLog();
                msgHandleLog.setMsgId(msgId);
                msgHandleLog.setPushChannelId(Long.valueOf(msgRecordVO.getPushChannelId()));
                msgHandleLog.setReceiverType(msgRecordVO.getReceiveRangeInfo().getRangeType());
                msgHandleLog.setPushResultCode(PushResultEnum.PUSH_SUCCESS.getErrorCode());
                msgHandleLog.setPushResultDescription(PushResultEnum.PUSH_SUCCESS.getDescription());
                msgHandleLogService.updatePushResult(msgHandleLog, receiverList);
            }
            // 5.更新消息记录表中的状态,pushResultCode都为1时说明所有人发送成功
            Set<Integer> pushResultCodeSet = results.stream().map(MsgMiddleResult::getPushResultCode).collect(Collectors.toSet());
            if (CollectionUtils.isNotEmpty(pushResultCodeSet)
                    && pushResultCodeSet.size() == 1
                    && PushResultEnum.PUSH_SUCCESS.getErrorCode().equals(pushResultCodeSet.iterator().next())) {
                msgRecordVO.setStatus(true);
                msgRecordService.updateMsgRecordStatus(msgRecordVO);
            }
        }
        // 6.处理响应信息
        return processResultMap(msgRecordVOList);
    }

    private ResultMap<MsgPushResponseDTO> processResultMap(List<MsgRecordVO> msgRecordVOList) {
        MsgRecordVO msgRecordVO = msgRecordVOList.get(0);
        MsgPushResponseDTO msgPushResponseDTO = new MsgPushResponseDTO();
        msgPushResponseDTO.setOrgMessageId(msgRecordVO.getUniqueId());
        msgPushResponseDTO.setNcMessageId(String.valueOf(msgRecordVO.getMsgId()));
        List<MsgMiddleResult> results = new ArrayList<>();
        msgRecordVOList.forEach(
                msgRecordVO1 -> {
                    List<MsgMiddleResult> msgMiddleResults = msgRecordVO.getResults();
                    if (CollectionUtils.isNotEmpty(msgMiddleResults)) {
                        results.addAll(msgMiddleResults);
                    }
                }
        );
        if (CollectionUtils.isEmpty(results)) {
            return new ResultMap<>(msgPushResponseDTO);
        }
        Set<Integer> pushResultCodeSet = results.stream().map(MsgMiddleResult::getPushResultCode).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(pushResultCodeSet)
                && pushResultCodeSet.size() == 1
                && PushResultEnum.PUSH_SUCCESS.getErrorCode().equals(pushResultCodeSet.iterator().next())) {
            return new ResultMap<>(msgPushResponseDTO);
        }
        StringBuilder errMessage = new StringBuilder();
        results.forEach(
                msgMiddleResult -> {
                    errMessage.append(msgMiddleResult.getPushResultDescription()).append(";");
                }
        );
        ResultMap<MsgPushResponseDTO> resultMap = new ResultMap<>();
        resultMap.setSuccess(false);
        resultMap.setErrMsg(errMessage.substring(0, errMessage.length() - 1));
        return resultMap;
    }

    private void msgRecordDTOParamCheck(MsgPushDTO.MsgRecordDTO msgRecordDTO) {
        // 获取请求头中数据
        HttpServletRequest request = SpringContextUtils.getRequest();
        String tenantCode = request.getHeader("tenantCode");
        String userId = request.getHeader("userId");
        String secretKey = request.getHeader("secretKey");
        if (StringUtils.isBlank(tenantCode) && StringUtils.isBlank(userId)) {
            throw new BaseException(CommonErrorCode.TETANT_USER_ISNULL);
        }
        if (StringUtils.isBlank(tenantCode)) {
            // 火眼侧不传租户编码，只传用户id的话转换用户id为租户id，且火眼一个用户只能对应一个租户
            List<BaseTenantUserDTO> baseTenantUserDTOList = baseTenantUserRepository.getBaseTenantUserDTOByUserId(userId);
            if (CollectionUtils.isEmpty(baseTenantUserDTOList)) {
                throw new BaseException(CommonErrorCode.TETANT_USER_NOTEXIT);
            }
            tenantCode = baseTenantUserDTOList.get(0).getTenantCode();
        }
        // 校验租户密钥
        BaseTenantDTO baseTenantDTO = baseTenantService.getByTenantCode(tenantCode);
        if (Objects.isNull(baseTenantDTO) || !StringUtils.equals(secretKey, baseTenantDTO.getKeyName())) {
            throw new BaseException(CommonErrorCode.TETANT_SECRETKEY_NOTEXIT);
        }
        msgRecordDTO.setTenantCode(tenantCode);
    }

    private void processReceiveChannel(MsgRecordVO msgRecordVO, MsgSource msgSource) {
        List<String> receiveChannelCodes = msgRecordVO.getReceiveChannelCodes();
        List<PushChannelInfo> pushChannelInfoList;
        if (CollectionUtils.isEmpty(receiveChannelCodes)) {
            // 1.消息源有效性验证
            msgSourceCheck(msgSource);
            // 2.从消息源获取渠道编码
            pushChannelInfoList = msgSourceService.getPushChannelByMsgSourceId(msgSource.getMsgSourceId());
            // 3.将消息源中关键数据填入MsgRecordVO中
            msgRecordVO.setMsgSourceName(msgSource.getSourceName())
                    .setOwnerDept(msgSource.getOwnerDept())
                    .setOwnerDeptName(msgSource.getOwnerDeptName());
        } else {
            // 根据渠道编码获取渠道id，消息记录表需要用到id
            pushChannelInfoList = pushChannelMap.getChannelInfoByChannelCodeList(receiveChannelCodes, msgRecordVO.getTenantCode());
        }
        if (CollectionUtils.isEmpty(pushChannelInfoList)) {
            throw new BaseException(CommonErrorCode.RECEIVECHANNEL_IS_EMPTY);
        }
        pushChannelInfoList = pushChannelInfoList.stream().filter(pushChannelInfo -> msgRecordVO.getTenantCode().equals(pushChannelInfo.getTenantCode())).collect(Collectors.toList());
        // 根据租户过滤后再验证
        if (CollectionUtils.isEmpty(pushChannelInfoList)) {
            throw new BaseException(CommonErrorCode.RECEIVECHANNEL_IS_EMPTY);
        }
        List<Long> pushChannelIdList = pushChannelInfoList.stream().map(PushChannelInfo::getPushChannelId).collect(Collectors.toList());
        List<String> pushChannelCodeList = pushChannelInfoList.stream().map(PushChannelInfo::getChannelCode).collect(Collectors.toList());
        List<Integer> pushChannelTypeList = pushChannelInfoList.stream().map(PushChannelInfo::getChannelType).collect(Collectors.toList());
        List<String> pushChannelNameList = pushChannelInfoList.stream().map(PushChannelInfo::getDescription).collect(Collectors.toList());
        receiveChannelCodes = pushChannelInfoList.stream().map(PushChannelInfo::getChannelCode).collect(Collectors.toList());
        msgRecordVO.setReceiveChannelCodes(receiveChannelCodes);
        msgRecordVO.setPushChannelId(StringUtils.join(pushChannelIdList, ","));
        msgRecordVO.setPushChannelCode(StringUtils.join(pushChannelCodeList, ","));
        msgRecordVO.setPushChannelType(StringUtils.join(pushChannelTypeList, ","));
        msgRecordVO.setPushChannelName(StringUtils.join(pushChannelNameList, ","));
        // 设置预置渠道信息
        msgRecordVO.setPushChannelInfoList(pushChannelInfoList);
    }

    private void processContents(MsgRecordVO msgRecordVO, MsgPushDTO.MsgRecordDTO msgRecordDTO, MsgSource msgSource) {
        MsgPushDTO.MsgRecordDTO.MessageInfo messageInfo = msgRecordDTO.getMessageInfo();
        String messageTransType = messageInfo.getMessageTransType();
        String messageContent = messageInfo.getMessageContent();
        String messageSubject = messageInfo.getMessageSubject();
        String messageAttachment = messageInfo.getMessageAttachment();
        String templateCode = messageInfo.getTemplateCode();
        String content = "";
        BaseMessageTemplateDTO baseMessageTemplateDTO = null;
        // 1.判断传输报文中是否有消息内容/消息模板
        if (StringUtils.isNotBlank(messageContent) || StringUtils.isNotBlank(templateCode)) {
            // 根据messageTransType处理传输内容
            // 传内容
            if (PushConstant.CONTENT_MESSAGE_TRANS_TYPE.equals(messageTransType)) {
                content = messageContent;
            }
            // 传模板
            if (PushConstant.TEMPLATE_MESSAGE_TRANS_TYPE.equals(messageTransType)) {
                MessageTemplateQuery qry = new MessageTemplateQuery();
                qry.setTemplateCode(templateCode);
                qry.setTenantCode(msgRecordVO.getTenantCode());
                qry.setIsEnabled(IsEnabledEnum.Y.getCode());
                qry.setIsDeleted("N");
                baseMessageTemplateDTO = baseMessageTemplateService.getTemplate(qry);
                if (Objects.isNull(baseMessageTemplateDTO)) {
                    throw new BaseException(CommonErrorCode.MSG_TEMPLATE_ISNULL);
                }
                if (StringUtils.isNotBlank(messageContent)) {
                    // 参数中messageContent不为空时，则使用参数中的messageContent
                    baseMessageTemplateDTO.setTemplateContent(messageContent);
                }
                // 处理模板参数
                content = dealTemplateParams(messageInfo, baseMessageTemplateDTO);
            }
        } else if (ObjectUtils.isEmpty(messageInfo.getLinkCard())) {
            // 2.传输报文中没有消息内容/消息模板，则从消息源中获取消息模板
            // String sourceId = msgRecordVO.getSourceId();
            // msgSource = msgSourceService.getMsgSourceBySourceCode(sourceId);
            // 消息源有效性验证
            msgSourceCheck(msgSource);
            MessageTemplateQuery qry = new MessageTemplateQuery();
            qry.setTemplateCode(msgSource.getTemplateCode());
            qry.setTenantCode(msgRecordVO.getTenantCode());
            qry.setIsEnabled(IsEnabledEnum.Y.getCode());
            qry.setIsDeleted("N");
            baseMessageTemplateDTO = baseMessageTemplateService.getTemplate(qry);
            if (Objects.isNull(baseMessageTemplateDTO)) {
                throw new BaseException(CommonErrorCode.MSG_TEMPLATE_ISNULL);
            }
            // 传输消息主题为空，并且为模板消息时使用模板标题
            if (StringUtils.isBlank(messageSubject)) {
                messageSubject = baseMessageTemplateDTO.getTemplateTitle();
            }
            // 处理模板参数
            content = dealTemplateParams(messageInfo, baseMessageTemplateDTO);
        }
        List<MsgBody> contents = new ArrayList<>();
        MsgBody msgBody = new MsgBody();
        //支持link_card和text
        if (PushConstant.CONTENT_MESSAGE_LINK_CARD.equals(messageTransType)) {
            msgBody.setType(MediaLimitEnum.LINK_CARD.name().toLowerCase());
            MsgPushDTO.LinkCard linkCard = messageInfo.getLinkCard();
            linkCard.setFromName("");
            linkCard.setFromIconLink("link");
            msgBody.setContent(JSONObject.toJSONString(linkCard));
        } else {
            msgBody.setType(MediaLimitEnum.TEXT.name().toLowerCase());
            msgBody.setContent(content);
        }
        contents.add(msgBody);
        msgRecordVO.setContents(contents);
        // 消息主题
        if (StringUtils.isNotBlank(messageSubject)) {
            msgRecordVO.setSubject(messageSubject);
            msgRecordVO.setMsgTitle(messageSubject);
        }
        // 消息附件
        if (StringUtils.isNotBlank(messageAttachment)) {
            msgRecordVO.setAttachmentAddress(messageAttachment);
        }
        baseMessageTemplateDTO = Optional.ofNullable(baseMessageTemplateDTO).orElseGet(BaseMessageTemplateDTO::new);
        msgRecordVO.setTemplateId(baseMessageTemplateDTO.getId());
        msgRecordVO.setTemplateName(baseMessageTemplateDTO.getTemplateName());
    }

    private String dealTemplateParams(MsgPushDTO.MsgRecordDTO.MessageInfo messageInfo, BaseMessageTemplateDTO baseMessageTemplateDTO) {
        String content;
        JSONObject templateParams = messageInfo.getTemplateParams();
        if (MapUtils.isNotEmpty(templateParams)) {
            List<BaseMessageTemplateParamDTO> baseMessageTemplateParamList = new ArrayList<>();
            for (Map.Entry<String, Object> entry : templateParams.entrySet()) {
                BaseMessageTemplateParamDTO baseMessageTemplateParamDTO = new BaseMessageTemplateParamDTO();
                baseMessageTemplateParamDTO.setParamName(entry.getKey());
                baseMessageTemplateParamDTO.setParamDescription(entry.getValue().toString());
                baseMessageTemplateParamList.add(baseMessageTemplateParamDTO);
            }
            baseMessageTemplateDTO.setBaseMessageTemplateParamList(baseMessageTemplateParamList);
        }
        content = processTemplateContent(baseMessageTemplateDTO);
        return content;
    }

    /**
     * 使用模板的，处理模板内容
     *
     * @param baseMessageTemplateDTO
     * @return
     */
    private String processTemplateContent(BaseMessageTemplateDTO baseMessageTemplateDTO) {
        if (Objects.isNull(baseMessageTemplateDTO)) {
            throw new BaseException(CommonErrorCode.MSG_TEMPLATE_ISNULL);
        }
        // 2.获取模板参数
        String templateContent = baseMessageTemplateDTO.getTemplateContent();
        List<BaseMessageTemplateParamDTO> baseMessageTemplateParamList = baseMessageTemplateDTO.getBaseMessageTemplateParamList();
        if (CollectionUtils.isEmpty(baseMessageTemplateParamList)) {
            // 参数中无模板参数，则从数据库获取
            baseMessageTemplateParamList = baseMessageTemplateParamService.selectByTemplateId(baseMessageTemplateDTO.getId());
        }
        Map<String, String> baseMessageTemplateParamDTOMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(baseMessageTemplateParamList)) {
            baseMessageTemplateParamList.forEach(
                    baseMessageTemplateParamDTO -> baseMessageTemplateParamDTOMap.put(baseMessageTemplateParamDTO.getParamName(), baseMessageTemplateParamDTO.getParamDescription())
            );
        }
        //3.替换模板内容
        return PlaceHolderUtils.parse(templateContent, baseMessageTemplateParamDTOMap);
    }

    private void msgRecordVoParamCheck(MsgRecordVO msgRecordVO) {
        if (null == msgRecordVO.getMsgTitle()) {
            throw new BaseException(CommonErrorCode.MSG_RECORD_TITLE);
        }
        if (null == msgRecordVO.getMsgDescription()) {
            throw new BaseException(CommonErrorCode.MSG_RECORD_DESCRIPTION);
        }
        if (CollectionUtils.isEmpty(msgRecordVO.getContents())) {
            throw new BaseException(CommonErrorCode.MSG_RECORD_CONTENTS);
        }
    }

//    private void msgPushVoParamCheck(MsgPushVO msgPushVO) {
//        if (null == msgPushVO.getMsgSourceId()) {
//            throw new BaseException(CommonErrorCode.MSG_SOURCE_NOTNULL);
//        }
//        List<MsgRecordVO> msgList = msgPushVO.getMsgList();
//        if (CollectionUtils.isEmpty(msgList)) {
//            throw new BaseException(CommonErrorCode.MSGLIST);
//        }
//        if (msgList.size() > 10) {
//            throw new BaseException(CommonErrorCode.MSGLIST_SIZE);
//        }
//        for (MsgRecordVO msgRecordVO : msgList) {
//            msgRecordVoParamCheck(msgRecordVO);
//        }
//    }

    private void insertInterfaceLogNew(MsgRecordVO msgRecordVO, MsgSource msgSource) {
        List<InterfaceLog> interfaceLogList = new ArrayList<>();
        List<Receiver> receivers = msgRecordVO.getReceivers();
        // 多渠道
        String pushChannelIds = msgRecordVO.getPushChannelId();
        String pushChannelTypes = msgRecordVO.getPushChannelType();
        String pushChannelNames = msgRecordVO.getPushChannelName();
        String[] pushUserIdArr = pushChannelIds.split(",");
        String[] pushChannelTypeArr = pushChannelTypes.split(",");
        String[] pushChannelNameArr = pushChannelNames.split(",");
        for (Receiver receiver : receivers) {
            for (int i = 0; i < pushUserIdArr.length; i++) {
                String pushUserIdStr = pushUserIdArr[i];
                String pushChannelType = pushChannelTypeArr[i];
                String pushChannelName = pushChannelNameArr[i];
                InterfaceLog interfaceLog = new InterfaceLog().setMsgSourceId(msgSource == null ? "" : msgSource.getSourceCode())
                        .setOperater(receiver.getReceiverName())
                        .setOperateDept(msgSource == null ? "" : msgSource.getOwnerDept())
                        .setOperateDeptName(msgSource == null ? "" : msgSource.getOwnerDeptName())
                        .setOperateTime(new Date())
                        .setPushChannelId(Integer.valueOf(pushUserIdStr))
                        .setPushChannelType(Integer.valueOf(pushChannelType))
                        .setPushChannelName(pushChannelName);
                if (StringUtils.isBlank(interfaceLog.getOperater())) {
                    logger.info("pushUserId中的name为空，写入key");
                    String operater = "";
                    String receiverId = receiver.getReceiverId();
                    String receiverMobilePhone = receiver.getReceiverMobilePhone();
                    String receiverEmail = receiver.getReceiverEmail();
                    String employeeCode = receiver.getEmployeeCode();
                    if (StringUtils.isNotBlank(receiverId)) {
                        operater = receiverId;
                    } else if (StringUtils.isNotBlank(receiverMobilePhone)) {
                        operater = receiverMobilePhone;
                    } else if (StringUtils.isNotBlank(receiverEmail)) {
                        operater = receiverEmail;
                    } else if (StringUtils.isNotBlank(employeeCode)) {
                        operater = employeeCode;
                    }
                    interfaceLog.setOperater(operater);
                }
                interfaceLogList.add(interfaceLog);
            }
        }
        interFaceLogService.insertSelective(interfaceLogList);
    }

//    private void insertInterfaceLog(MsgPushVO msgPushVO) {
//        List<InterfaceLog> interfaceLogList = new ArrayList<>();
//        String msgSourceId = msgPushVO.getMsgSourceId();
//        MsgSource msgSource = msgSourceService.getMsgSourceBySourceCode(msgSourceId);
//        List<MsgRecordVO> msgList = msgPushVO.getMsgList();
//        for (MsgRecordVO msgRecordVO : msgList) {
//            List<Receiver> receivers = msgRecordVO.getReceivers();
//            for (Receiver receiver : receivers) {
//                // 多渠道
//                String pushChannelIds = msgRecordVO.getPushChannelId();
//                String pushChannelTypes = msgRecordVO.getPushChannelType();
//                String pushChannelNames = msgRecordVO.getPushChannelName();
//                String[] pushUserIdArr = pushChannelIds.split(",");
//                String[] pushChannelTypeArr = pushChannelTypes.split(",");
//                String[] pushChannelNameArr = pushChannelNames.split(",");
//                for (int i = 0; i < pushUserIdArr.length; i++) {
//                    String pushUserIdStr = pushUserIdArr[i];
//                    String pushChannelType = pushChannelTypeArr[i];
//                    String pushChannelName = pushChannelNameArr[i];
//                    InterfaceLog interfaceLog = new InterfaceLog().setMsgSourceId(msgPushVO.getMsgSourceId())
//                            .setOperater(receiver.getReceiverName())
//                            .setOperateDept(msgSource == null ? "" : msgSource.getOwnerDept())
//                            .setOperateDeptName(msgSource == null ? "" : msgSource.getOwnerDeptName())
//                            .setOperateTime(new Date())
//                            .setPushChannelId(Integer.valueOf(pushUserIdStr))
//                            .setPushChannelType(Integer.valueOf(pushChannelType))
//                            .setPushChannelName(pushChannelName);
//                    if (StringUtils.isBlank(interfaceLog.getOperater())) {
//                        logger.info("pushUserId中的name为空，写入key");
//                        String operater = "";
//                        String receiverId = receiver.getReceiverId();
//                        String receiverMobilePhone = receiver.getReceiverMobilePhone();
//                        String receiverEmail = receiver.getReceiverEmail();
//                        String employeeCode = receiver.getEmployeeCode();
//                        if (StringUtils.isNotBlank(receiverId)) {
//                            operater = receiverId;
//                        } else if (StringUtils.isNotBlank(receiverMobilePhone)) {
//                            operater = receiverMobilePhone;
//                        } else if (StringUtils.isNotBlank(receiverEmail)) {
//                            operater = receiverEmail;
//                        } else if (StringUtils.isNotBlank(employeeCode)) {
//                            operater = employeeCode;
//                        }
//                        interfaceLog.setOperater(operater);
//                    }
//                    interfaceLogList.add(interfaceLog);
//                }
//            }
//        }
//        //OperateLogUtil.logAuditHandle(msgSource, request, msgPushVO);
//        interFaceLogService.insertSelective(interfaceLogList);
//
//    }

    /**
     * mq处理流程
     * 1.解析mq中的msg 主键信息表
     * 2.查询数据库获得相应的数据
     * 3.推送处理
     *
     * @param msgBody
     */
    @Override
    public void mqPush(String msgBody) {
        // 获取ID List
        List<MsgRecordVO> msgRecordVos = JSON.parseArray(msgBody, MsgRecordVO.class);
        MsgSource msgSource = msgSourceService.getMsgSourceBySourceCode(PushConstant.MSG_ZNTS_ID);
        for (MsgRecordVO msgRecordVO : msgRecordVos) {
            /*msgRecordVO.setMsgSourceId(PushConstant.MSG_ZNTS_ID)
                    .setMsgSourceName(PushConstant.MSG_ZNTS_NAME)
                    .setMsgSourceType(PushConstant.ZNTS_MSG_SOURCE_TYPE);*/
        }
        // push(msgRecordVos, msgSource);
    }


    private String dealChannelType(Integer monitorChannelType) {
        //监控渠道类型 1 政务微信 2 app 3 网页客户端 4 短信 5 邮件
        String msg = "";
        switch (monitorChannelType) {
            case 1:
                msg = "政务微信";
                break;
            case 2:
                msg = "app";
                break;
            case 3:
                msg = "网页客户端";
                break;
            case 4:
                msg = "短信";
                break;
            case 5:
                msg = "邮件";
                break;
            default:
                break;
        }
        return msg;
    }

    /**
     * 数据源是否可用检查
     *
     * @param msgSource
     */
    private void msgSourceCheck(MsgSource msgSource) {
        if (msgSource == null) {
            throw new BaseException(CommonErrorCode.MSG_SOURCE_INVAILD);
        }
        if (IsEnabledEnum.N.getCode().equals(msgSource.getIsEnabled())) {
            throw new BaseException(CommonErrorCode.MSG_SOURCE_ISNOTENABLED);
        }
        Integer sourceType = msgSource.getSourceType();
        SourceTypeEnum sourceTypeEnum = SourceTypeEnum.valueofType(sourceType);
        // 此刻
        long now = System.currentTimeMillis();
        switch (Objects.requireNonNull(sourceTypeEnum)) {
            case ONE_YEAR:
            case ONE_MONTH:
            case ONE_WEEK:
            case ONE_DAY:
            case CUSTOM:
                // 开始时间
                logger.info(" 消息源有效期开始时间 {} ", msgSource.getStartTime());
                long startTimestamp = msgSource.getStartTime().getTime() - 1000 * 60 * 5;
                boolean isStart = now >= startTimestamp;
                // 结束时间
                logger.info(" 消息源有效期结束时间 {} ", msgSource.getEndTime());
                long endTimestamp = msgSource.getEndTime().getTime();
                boolean notEnd = now < endTimestamp;
                if (!(isStart && notEnd)) {
                    throw new BaseException(CommonErrorCode.MSG_SOURCE_EXPIRE);
                }
                break;
            default:
                break;
        }

    }

}
